using System.Windows.Forms;
using NUnit.Framework;
using Rhino.Mocks;

namespace ShadeTree.Binding.Tests
{
    [TestFixture]
    public class ScreenStateMachineTester
    {
        #region Setup/Teardown

        [SetUp]
        public void SetUp()
        {
            _mocks = new MockRepository();
            _binder = _mocks.StrictMock<IScreenBinder>();

            string text = "";

            _control1 = new Control(text);
            _control2 = new Control(text);
            _control3 = new Control(text);
            _control4 = new Control(text);
            _control5 = new Control(text);
            _control6 = new Control(text);

            _machine = new ScreenStateMachine<StateEnum>(_binder);

            _machine.OnStateChangeTo(StateEnum.State1).Enable(_control1, _control2);
            _machine.OnStateChangeTo(StateEnum.State2).DisableAllBut(_control2, _control5);
            _machine.OnStateChangeTo(StateEnum.State3).Enable(_control1, _control4);
            _machine.OnStateChangeTo(StateEnum.State4).Enable(_control5, _control6);
            _machine.OnStateChangeTo(StateEnum.State5).EnableAll();
            _machine.OnStateChangeTo(StateEnum.State6).EnableAllBut(_control1, _control2);
        }

        #endregion

        private Control _control1;
        private Control _control2;
        private Control _control3;
        private Control _control4;
        private Control _control5;
        private Control _control6;
        private MockRepository _mocks;
        private IScreenBinder _binder;
        private ScreenStateMachine<StateEnum> _machine;

        public enum StateEnum
        {
            State1,
            State2,
            State3,
            State4,
            State5,
            State6
        }

        [Test]
        public void DisableAllButState_enables_only_its_controls_and_disables_all_the_other_controls()
        {
            IScreenState state = _machine.GetState(StateEnum.State2);

            state.IsControlEnabled(_control1).ShouldBeFalse();
            state.IsControlEnabled(_control2).ShouldBeTrue();
            state.IsControlEnabled(_control3).ShouldBeFalse();
            state.IsControlEnabled(_control4).ShouldBeFalse();
            state.IsControlEnabled(_control5).ShouldBeTrue();
            state.IsControlEnabled(_control6).ShouldBeFalse();
        }

        [Test]
        public void EnableAll_enables_all_controls()
        {
            IScreenState state = _machine.GetState(StateEnum.State5);

            state.IsControlEnabled(_control1).ShouldBeTrue();
            state.IsControlEnabled(_control2).ShouldBeTrue();
            state.IsControlEnabled(_control3).ShouldBeTrue();
            state.IsControlEnabled(_control4).ShouldBeTrue();
            state.IsControlEnabled(_control5).ShouldBeTrue();
            state.IsControlEnabled(_control6).ShouldBeTrue();
        }

        [Test]
        public void EnableAllButSomeControls()
        {
            IScreenState state = _machine.GetState(StateEnum.State6);

            state.IsControlEnabled(_control1).ShouldBeFalse();
            state.IsControlEnabled(_control2).ShouldBeFalse();
            state.IsControlEnabled(_control3).ShouldBeTrue();
            state.IsControlEnabled(_control4).ShouldBeTrue();
            state.IsControlEnabled(_control5).ShouldBeTrue();
            state.IsControlEnabled(_control6).ShouldBeTrue();
        }

        [Test]
        public void MarkElementAsReadOnly()
        {
            var control = new Control();
            using (_mocks.Record())
            {
                var element = _mocks.StrictMock<IScreenElement>();
                Expect.Call(_binder.FindElementForControl(control)).Return(element);
                element.ActivationMode = ActivationMode.ReadOnly;
                element.EnableControl(_machine.CurrentState);
            }

            using (_mocks.Playback())
            {
                _machine.MarkElementAsReadOnly(control);
            }
        }


        [Test]
        public void MarkElementForNormalActivation()
        {
            var control = new Control();
            using (_mocks.Record())
            {
                var element = _mocks.StrictMock<IScreenElement>();
                Expect.Call(_binder.FindElementForControl(control)).Return(element);
                element.ActivationMode = ActivationMode.Normal;
                element.EnableControl(_machine.CurrentState);
            }

            using (_mocks.Playback())
            {
                _machine.MarkElementForNormalActivation(control);
            }
        }

        [Test]
        public void NormalState1_enables_its_controls_and_disables_all_the_other_controls_from_other_normal_states()
        {
            IScreenState state = _machine.GetState(StateEnum.State1);

            state.IsControlEnabled(_control1).ShouldBeTrue();
            state.IsControlEnabled(_control2).ShouldBeTrue();
            state.IsControlEnabled(_control3).ShouldBeTrue();
            state.IsControlEnabled(_control4).ShouldBeFalse();
            state.IsControlEnabled(_control5).ShouldBeFalse();
            state.IsControlEnabled(_control6).ShouldBeFalse();
        }

        [Test]
        public void NormalState3_enables_its_controls_and_disables_all_the_other_controls_from_other_normal_states()
        {
            IScreenState state = _machine.GetState(StateEnum.State3);

            state.IsControlEnabled(_control1).ShouldBeTrue();
            state.IsControlEnabled(_control2).ShouldBeFalse();
            state.IsControlEnabled(_control3).ShouldBeTrue();
            state.IsControlEnabled(_control4).ShouldBeTrue();
            state.IsControlEnabled(_control5).ShouldBeFalse();
            state.IsControlEnabled(_control6).ShouldBeFalse();
        }

        [Test]
        public void NormalState4_enables_its_controls_and_disables_all_the_other_controls_from_other_normal_states()
        {
            IScreenState state = _machine.GetState(StateEnum.State4);

            state.IsControlEnabled(_control1).ShouldBeFalse();
            state.IsControlEnabled(_control2).ShouldBeFalse();
            state.IsControlEnabled(_control3).ShouldBeTrue();
            state.IsControlEnabled(_control4).ShouldBeFalse();
            state.IsControlEnabled(_control5).ShouldBeTrue();
            state.IsControlEnabled(_control6).ShouldBeTrue();
        }

        [Test]
        public void When_the_StateMachine_Has_its_state_changed_it_fetches_its_state_and_sends_it_to_its_IScreenBinder()
        {
            IScreenState state = _machine.GetState(StateEnum.State1);
            using (_mocks.Record())
            {
                _binder.EnableControls(state);
            }

            using (_mocks.Playback())
            {
                _machine.ChangeStateTo(StateEnum.State1);
            }
        }
    }
}